Behaivor

Behavior只有是CoordinatorLayout的直接子View才有意义。只要将Behavior绑定到CoordinatorLayout的直接子元素上,就能对触摸事件(touch events)、window insets、measurement、layout以及嵌套滚动(nested scrolling)等动作进行拦截。Design Library的大多功能都是借助Behavior的大量运用来实现的。当然,Behavior无法独立完成工作,必须与实际调用的CoordinatorLayout子视图相绑定。具体有三种方式:通过代码绑定、在XML中绑定或者通过注释实现自动绑定。上面NestedScrollView中app:layout_behavior=”@string/appbar_scrolling_view_behavior”的Behavior是系统默认的,我们也可以根据自己的需求来自定义Behavior。

自定义Behavior

  • 某个view监听另一个view的状态变化,例如大小、位置、显示状态等
    需要关系:layoutDependsOn和onDependentViewChanged方法,
  • 某个view监听CoordinatorLayout里的滑动状态
    需要关系:onStartNestedScroll和onNestedPreScroll方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    /**
    * 表示是否给应用了Behavior 的View 指定一个依赖的布局,通常,当依赖的View 布局发生变化时
    * 不管被被依赖View 的顺序怎样,被依赖的View也会重新布局
    * @param parent
    * @param child 绑定behavior 的View
    * @param dependency 依赖的view
    * @return 如果child 是依赖的指定的View 返回true,否则返回false
    */
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
    return super.layoutDependsOn(parent, child, dependency);
    }
    /**
    * 当被依赖的View 状态(如:位置、大小)发生变化时,这个方法被调用
    * @param parent
    * @param child
    * @param dependency
    * @return
    */
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
    return super.onDependentViewChanged(parent, child, dependency);
    }
    /**
    * 当coordinatorLayout 的子View试图开始嵌套滑动的时候被调用。当返回值为true的时候表明
    * coordinatorLayout 充当nested scroll parent 处理这次滑动,需要注意的是只有当返回值为true
    * 的时候,Behavior 才能收到后面的一些nested scroll 事件回调(如:onNestedPreScroll、onNestedScroll等)
    * 这个方法有个重要的参数nestedScrollAxes,表明处理的滑动的方向。
    *
    * @param coordinatorLayout 和Behavior 绑定的View的父CoordinatorLayout
    * @param child 和Behavior 绑定的View
    * @param directTargetChild
    * @param target
    * @param nestedScrollAxes 嵌套滑动 应用的滑动方向,看 {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
    * {@link ViewCompat#SCROLL_AXIS_VERTICAL}
    * @return
    */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
    return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }
    /**
    * 嵌套滚动发生之前被调用
    * 在nested scroll child 消费掉自己的滚动距离之前,嵌套滚动每次被nested scroll child
    * 更新都会调用onNestedPreScroll。注意有个重要的参数consumed,可以修改这个数组表示你消费
    * 了多少距离。假设用户滑动了100px,child 做了90px 的位移,你需要把 consumed[1]的值改成90,
    * 这样coordinatorLayout就能知道只处理剩下的10px的滚动。
    * @param coordinatorLayout
    * @param child
    * @param target
    * @param dx 用户水平方向的滚动距离
    * @param dy 用户竖直方向的滚动距离
    * @param consumed
    */
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
    super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    }
    /**
    * 进行嵌套滚动时被调用
    * @param coordinatorLayout
    * @param child
    * @param target
    * @param dxConsumed target 已经消费的x方向的距离
    * @param dyConsumed target 已经消费的y方向的距离
    * @param dxUnconsumed x 方向剩下的滚动距离
    * @param dyUnconsumed y 方向剩下的滚动距离
    */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
    super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
    }
    /**
    * 嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。
    * @param coordinatorLayout
    * @param child
    * @param target
    */
    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
    super.onStopNestedScroll(coordinatorLayout, child, target);
    }
    /**
    * onStartNestedScroll返回true才会触发这个方法,接受滚动处理后回调,可以在这个
    * 方法里做一些准备工作,如一些状态的重置等。
    * @param coordinatorLayout
    * @param child
    * @param directTargetChild
    * @param target
    * @param nestedScrollAxes
    */
    @Override
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
    super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }
    /**
    * 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些速度信息
    * 决定最终状态,比如滚动Header,是让Header处于展开状态还是折叠状态。返回true 表
    * 示消费了fling.
    *
    * @param coordinatorLayout
    * @param child
    * @param target
    * @param velocityX x 方向的速度
    * @param velocityY y 方向的速度
    * @return
    */
    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {
    return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }
    //可以重写这个方法对子View 进行重新布局
    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
    return super.onLayoutChild(parent, child, layoutDirection);
    }